﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml.Linq;

namespace LibTracker
{
    public class ResultRequestFromPostService
    {
        public string TrackNumber { get; set; }
        public IList<PostRecord> Records { get; set; }
    }


    public class TrackNumber : ITrackNumber
    {
        private const string _trackReplace = "[TRACKNO]";
        private ManualResetEvent _doneEvent;

        private int _threadNum;

        public IPostDataSet DataSource { get; set; }

        public TrackNumber(IPostDataSet aDataSource, ManualResetEvent aDoneEvent)
        {
            DataSource = aDataSource;
            _doneEvent = aDoneEvent;
        }


        public ResultRequestFromPostService GetRecordsFromPostServices()
        {
            _threadNum = Thread.CurrentThread.GetHashCode();
            Debug.WriteLine(String.Format("Поток {0}: Метод ResultRequestFromPostService: Вход", _threadNum));
            var postServices = DataSource.GetPostServices();

            IList<PostRecord> records = new List<PostRecord>();

            int iter = 0;
            foreach (var postServiceInfo in postServices)
            {
                Debug.WriteLine(String.Format("Поток {0}: Метод ResultRequestFromPostService: Вызываем ParseHTML {1}", _threadNum, iter++));
                ParseHTML(records, postServiceInfo);
            }

            Debug.WriteLine(String.Format("Поток {0}: Метод GetRecordsFromPostServices: Завершен", _threadNum));
            _doneEvent.Set();
            return new ResultRequestFromPostService() { Records = records, TrackNumber = DataSource.TrackNumber };
        }

        public XDocument GetXmlRecordsFromPostServices()
        {
            throw new NotImplementedException();
        }


        private void ParseHTML(IList<PostRecord> aRecords, PostServiceInfo aPostServiceInfo)
        {
            Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Вход", _threadNum));
             
            Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Формируем строку запроса", _threadNum));
            string queryStr = String.Empty;

            if (!string.IsNullOrEmpty(aPostServiceInfo.Postflds))
            {
                queryStr = aPostServiceInfo.Url + "?" +
                    aPostServiceInfo.Postflds.Replace(_trackReplace, DataSource.TrackNumber);
            }
            else
            {
                queryStr = aPostServiceInfo.Url.Replace(_trackReplace, DataSource.TrackNumber);
            }

            Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Получаем HTML код", _threadNum));
            // Получаем HTML код
            StreamReader stream;
            string htmlStr;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(queryStr);
            if (!string.IsNullOrEmpty(aPostServiceInfo.HDRS))
            {
                //request.Headers.Add(aPostServiceInfo.HDRS);
            }

            try
            {
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    //stream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("windows-1251"));
                    stream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8"));
                    htmlStr = stream.ReadToEnd();
                }

            }
            catch (WebException err)
            {
                Debug.WriteLine(String.Format("Поток {0}: Метод GetPostServices: {1}",
                                              Thread.CurrentThread.GetHashCode(), err.Message));
                Debug.WriteLine(queryStr);
                return;
            }
            Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Находим совпадения (парсим)", _threadNum));

            MatchCollection match = null;
            if (aPostServiceInfo.Info != null)
            {
                try
                {
                    match = Regex.Matches(htmlStr, aPostServiceInfo.Info, RegexOptions.IgnoreCase);
                }
                catch (Exception err)
                {

                    Debug.WriteLine(String.Format("Поток {0}: Метод GetPostServices: {1}",
                                              Thread.CurrentThread.GetHashCode(), err.Message));
                }
            }

            if (match != null)
            {
                foreach (Match v in match)
                {
                    PostRecord postRecord = new PostRecord();

                    Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Определяем дату", _threadNum));

                    #region Определяем дату

                    if (aPostServiceInfo.DateSe != null && aPostServiceInfo.DateDlm != null)
                        if (aPostServiceInfo.DateSe.IndexOf(';') >= 0)
                        {
                            // парсим строку с индексами "2;3;4"

                            int arrLen = Regex.Matches(aPostServiceInfo.DateSe, ";").Count;

                            int[] indexs = new int[arrLen];
                            string tmp = aPostServiceInfo.DateSe;
                            int i = 0;
                            do
                            {
                                int idxEnd = aPostServiceInfo.DateSe.IndexOf(';') >= 0
                                                 ? tmp.IndexOf(';')
                                                 : tmp.Length;

                                indexs[i] = int.Parse(tmp.Substring(0, idxEnd));


                                tmp = tmp.Remove(0, idxEnd);
                                i++;
                            } while (i < arrLen && tmp.Length != 0);

                            tmp = String.Empty;
                            for (int j = 0; j < indexs.Length; j++)
                            {
                                tmp += v.Groups[indexs[j]].Value;
                                tmp += (j != indexs.Length - 1) ? aPostServiceInfo.DateDlm : "";
                            }

                            // если не проканает придется юзать маску 
                            // и по ней парсить либо скаcтить маску под формат c#
                            postRecord.Date = DateTime.Parse(tmp);

                        }
                        else if (aPostServiceInfo.DateSe.Length == 1)
                        {
                            int indexGroup = Convert.ToInt32(aPostServiceInfo.DateSe);
                            string strDate = v.Groups[indexGroup].Value;
                            postRecord.Date = DateTime.Parse(strDate);
                        }
                        else
                        {
                            MatchCollection tmpMatch = Regex.Matches(v.ToString(), aPostServiceInfo.DateSe);
                            foreach (Match m in tmpMatch)
                            {
                                postRecord.Date = DateTime.Parse(m.Value);
                                break;
                            }
                            //postRecord.Date = DateTime.Parse(tmpMatch);
                            //if (aPostServiceInfo.DateSe.IndexOf(aPostServiceInfo.DateDlm[0]) >= 0)
                            //{
                            //    // здесь распарсим потом
                            //}
                        }

                    #endregion

                    Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Определяем время события", _threadNum));

                    #region Определяем время события

                    #endregion

                    Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Определяем id и наименование PostService", _threadNum));

                    #region Определяем id и наименование PostService

                    postRecord.PostServiceId = aPostServiceInfo.Id != null ? aPostServiceInfo.Id.Value : -1;
                    postRecord.PostServiceName = aPostServiceInfo.Name;

                    #endregion

                    Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Определяем тело записи", _threadNum));

                    #region Определяем тело записи

                    // парсим строку с индексами "2;3;4"
                    if (aPostServiceInfo.InfoSes != null)
                        if (aPostServiceInfo.InfoSes.IndexOf(';') > 0)
                        {
                            int arrLen = Regex.Matches(aPostServiceInfo.InfoSes, ";").Count;

                            int[] indexs = new int[arrLen];
                            string tmp = aPostServiceInfo.InfoSes;
                            int i = 0;
                            do
                            {
                                int idxEnd = aPostServiceInfo.InfoSes.IndexOf(';') >= 0
                                                 ? tmp.IndexOf(';')
                                                 : tmp.Length;

                                indexs[i] = int.Parse(tmp.Substring(0, idxEnd));


                                tmp = tmp.Remove(0, idxEnd);
                                i++;
                            } while (i < arrLen && tmp.Length != 0);

                            tmp = String.Empty;
                            for (int j = 0; j < indexs.Length; j++)
                            {
                                tmp += v.Groups[indexs[j]].Value + " ";
                            }

                            // если не проканает придется юзать маску 
                            // и по ней парсить либо скаcтить маску под формат c#
                            postRecord.Record = tmp;
                        }
                        else
                        {
                            postRecord.Record = v.Groups[int.Parse(aPostServiceInfo.InfoSes)].Value;
                        }

                    #endregion

                    Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Добавляем запись в aRecords", _threadNum));

                    aRecords.Add(postRecord);

                    Debug.WriteLine(String.Format("Поток {0}: Метод ParseHTML: Завершен", _threadNum));
                }
            }
        }

    }
}
